package com.joinway.framework.support.input;

import java.lang.annotation.Annotation;
import java.lang.reflect.Method;

import org.apache.commons.lang3.ArrayUtils;
import org.apache.commons.lang3.StringUtils;
import org.aspectj.lang.ProceedingJoinPoint;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.joinway.framework.core.utils.AopHelper;
import com.joinway.framework.support.input.annotation.Render;
import com.joinway.framework.support.input.type.Case;
import com.joinway.framework.support.input.type.Space;
import com.joinway.framework.support.utils.InterceptorHelper;

public class InputAspect {

	private final static Logger log = LoggerFactory.getLogger(InputAspect.class);
	
	public Object doAround(ProceedingJoinPoint point) throws Throwable {
		Object[] args = point.getArgs();
		
		try{
			args = processInput(point);
		}catch(Throwable t){
			log.warn("process input args failed, hence ignore, " + t.getMessage());
		}
		
		return point.proceed(args);
	}
	
	Object[] processInput(ProceedingJoinPoint point){
		Object[] args = point.getArgs();
		
		do{
			if(ArrayUtils.isEmpty(args)) break;
	
			Method method = AopHelper.getMethod(point);
			Annotation[][] anns = method.getParameterAnnotations();
			
			if(anns == null) break;
			
			for(int i = 0; i < args.length; i++) {
				Render render = InterceptorHelper.getParameterAnnotation(anns[i], Render.class);
				
				if(render != null){
					Object arg = processArg(args[i], render, i);
					
					args[i] = arg;
				}
			}
			
			
		}while(false);
		
		return args;
	}
	
	Object processArg(Object arg, Render render, int index){
		Object obj = processSpace(arg, render.value(), index);
		obj = processCase(obj, render.format(), index);
//		obj = processMonitor(obj, render.monitor(), index);
		
		return obj;
	}
	
	Object processSpace(Object arg, Space space, int index){
		Object o = arg;
		
		if(arg instanceof String){
			String s = (String)arg;
			
			if(Space.TrimToEmpty == space){
				s = StringUtils.trimToEmpty(s);
			}else if(Space.TrimToNull == space){
				s = StringUtils.trimToNull(s);
			}else if(Space.Trim == space){
				s = StringUtils.trim(s);
			}
			
			o = s;
		}
		
		return o;
	}
	
	Object processCase(Object arg, Case caze, int index){
		Object o = arg;
		
		if(arg instanceof String){
			String s = (String)arg;
			
			if(Case.Lower == caze){
				s = StringUtils.lowerCase(s);
			}else if(Case.Upper == caze){
				s = StringUtils.upperCase(s);
			}
			
			o = s;
		}
		
		return o;
	}
	
//	Object processMonitor(Object arg, Class<? extends InputMonitor> type, int index) {
//		if(type != null && !type.getName().equals(InputMonitor.class.getName())){
//			try {
//				InputMonitor im = type.newInstance();
//				im.watch(arg, index);
//			} catch (Exception e) {
//				log.warn("init input monitor {} failed, ignore input monitor for args[{}]", type.getSimpleName(), index);
//			}
//		}
//		return arg;
//	}
}
